package org.wtfbbq.net.wifi;

import java.util.*;
import java.util.regex.*;
import java.io.*;

class NetshHandler extends RadarHandler {

	private ArrayList<WirelessNetwork> wns = new ArrayList<WirelessNetwork>();
	
	public NetshHandler ( ) {
	
	}
	
	public ArrayList<WirelessNetwork> wirelessNetworks ( ) {
		_scan();
		return wns;
	}
	
	public ArrayList<AccessPoint> wirelessAccessPoints ( ) {
		_scan();
		ArrayList<AccessPoint> out = new ArrayList<AccessPoint>();
		
		for ( int i = 0 ; i < wns.size() ; i++ ) {
			AccessPoint[] tmp = wns.get(i).getAccessPoints();
			for ( int j = 0 ; j < tmp.length ; j++ ) {
				if ( ! out.contains( tmp[j] ) ) {
					out.add( tmp[j] );
				}
			}
		}
		return out;
	}
	
	protected int _scan ( ) {
		wns.clear();
		Process netsh;
		String interfaceName = "";
		int networks = 0;
		
		try {
			netsh = Runtime.getRuntime().exec("netsh wlan show networks mode=bssid");		
			BufferedReader br = new BufferedReader( new InputStreamReader ( netsh.getInputStream() ) );
			String tmp = "";
			
			// Output should start with a space ' '
			if ( ! br.readLine().equals( " " ) ) {
				throw new IOException ( "Unexpected output from process: space char expected" );
			}
			
			// Next the name of the adapter should appear
			if ( ( tmp = br.readLine() ).startsWith("Interface name :") ) {
				try {
					interfaceName = tmp.split(":")[1].trim();
				} catch ( ArrayIndexOutOfBoundsException ae ) {
					throw new IOException ( "Unexpected output from process: array index out of bounds" );
				}
			} else {
				throw new IOException ( "Unexpected output from process: Interface name expected" );
			}
			
			// Next the number of networks found
			if ( ( tmp = br.readLine() ).startsWith("There are") ) {
				try {
					networks = Integer.parseInt(tmp.split(" ")[2].trim());
				} catch ( NumberFormatException nfe ) {
					throw new IOException ( "Unexpected output from process: NaN when parsing number of networks" );
				} catch ( ArrayIndexOutOfBoundsException ai ) {
					throw new IOException ( "Unexpected output from process: array index out of bounds @ network count" );
				}
			}
			
			// An ampty line should be next
			if ( ! br.readLine().equals("") ) {
				throw new IOException( "Unexpected output from process: empty line expected" );
			}
			
			// Next should be an SSID this might occure a couple of times
			while ( ( tmp = br.readLine() ) != null && tmp.startsWith("SSID") ) {
				WirelessNetwork wn = new WirelessNetwork();
				
				// set ssid
				try {
					wn.setSSID( tmp.split(":")[1].trim() );
				} catch ( ArrayIndexOutOfBoundsException ai ) {
					throw new IOException ( "Unexpected output from process: array index out of bounds @ SSID" );
				}
				
				// Network type
				if ( ( tmp = br.readLine() ).trim().startsWith("Network type") ) {
					try {
						wn.setNetworkType( tmp.split(":")[1].trim() );
					} catch ( ArrayIndexOutOfBoundsException ai ) {
						throw new IOException ( "Unexpected output from process: array index out of bounds @ network type" );
					}
				} else {
					throw new IOException ( "Unexpected output from process: Network type expected" );
				}
				
				// Authentication
				if ( ( tmp = br.readLine() ).trim().startsWith("Authentication") ) {
					try {
						wn.setAuthentication( tmp.split(":")[1].trim() );
					} catch ( ArrayIndexOutOfBoundsException ai ) {
						throw new IOException ( "Unexpected output from process: array index out of bounds @ authentication" );
					}
				} else {
					throw new IOException ( "Unexpected output from process: Authentication expected" );
				}
				
				// Encryption
				if ( ( tmp = br.readLine() ).trim().startsWith("Encryption") ) {
					try {
						wn.setEncryption( tmp.split(":")[1].trim() );
					} catch ( ArrayIndexOutOfBoundsException ai ) {
						throw new IOException ( "Unexpected output from process: array index out of bounds @ encryption" );
					}
				} else {
					throw new IOException ( "Unexpected output from process: Encryption expected" );
				}
				
				tmp = br.readLine();
				
				// BSSID
				while ( true ) {
					AccessPoint ap = new AccessPoint();
					
					// BSSID
					if ( tmp.trim().startsWith("BSSID") ) {
						try {
							ap.setBSSID( tmp.split(" : ")[1].trim() );
						} catch ( ArrayIndexOutOfBoundsException ai ) {
							throw new IOException ( "Unexpected output from process: array index out of bounds @ bssid" );
						}
					} else {
						throw new IOException ( "Unexpected output from process: BSSID expected" );
					}
					
					// Signal
					if ( ( tmp = br.readLine() ).trim().startsWith("Signal") ) {
						try {
							ap.setSignal( tmp.split(":")[1].trim() );
						} catch ( ArrayIndexOutOfBoundsException ai ) {
							throw new IOException ( "Unexpected output from process: array index out of bounds @ signal" );
						}
					}
					
					// Radio Type
					if ( ( tmp = br.readLine() ).trim().startsWith("Radio type") ) {
						try {
							ap.setRadioType( tmp.split(":")[1].trim() );
						} catch ( ArrayIndexOutOfBoundsException ai ) {
							throw new IOException ( "Unexpected output from process: array index out of bounds @ radio type" );
						}
					}
					
					// Channel
					if ( ( tmp = br.readLine() ).trim().startsWith("Channel") ) {
						try {
							ap.setChannel( tmp.split(":")[1].trim() );
						} catch ( ArrayIndexOutOfBoundsException ai ) {
							throw new IOException ( "Unexpected output from process: array index out of bounds @ channel" );
						}
					}
					
					// Basic rates
					if ( ( tmp = br.readLine() ).trim().startsWith("Basic rates") ) {
						try {
							ap.setBasicRates( tmp.split(":")[1].trim() );
						} catch ( ArrayIndexOutOfBoundsException ai ) {
							throw new IOException ( "Unexpected output from process: array index out of bounds @ basic rates" );
						}
					}
					
					// Other rates
					if ( ( tmp = br.readLine() ).trim().startsWith("Other rates") ) {
						try {
							ap.setOtherRates( tmp.split(":")[1].trim() );
							wn.addAccessPoint(ap);
							if ( ( tmp = br.readLine() ).equals("") ) {
								break;
							}							
						} catch ( ArrayIndexOutOfBoundsException ai ) {
							throw new IOException ( "Unexpected output from process: array index out of bounds @ other rates" );
						}
					} else if ( tmp.equals("") ) {
						wn.addAccessPoint( ap );
						break;
					}
				}
				
				wns.add(wn);
			}

		} catch ( IOException io ) {
			System.out.println( "Error while executing netsh wlan show networks" );
			io.printStackTrace();
		}		
		return networks;
	}
	
	protected void _debugWirelessNetworks() {
		System.out.println ("\r\n---------------WiFi COL---------------\r\n");
		if ( wns.isEmpty() ) {
			System.out.println( "No networks in collection" );
			return;
		}
		
		for ( int i = 0 ; i < wns.size() ; i++ ) {
			System.out.println(wns.get(i));
		}
		System.out.println("\r\n---------------Wifi END---------------\r\n");
	}
	
	protected void _debugLine ( String line ) {
		if ( line == null ) {
			System.out.println ( "null" );
		} else {
			if ( line.equals("") ) {
				System.out.println( "empty line" );
			}
			System.out.println( line );
			for ( int i = 0 ; i < line.length() ; i++ ) {
				System.out.print("" + line.getBytes()[i] + ' ');
			}
			System.out.print("\r\n");
			System.out.flush();
		}
	}
	protected boolean _isEmpty ( String[] t ) {
		if ( t == null ) {
			return true;
		}
		if ( t.length == 0 ) {
			return true;
		}
		for ( int i = 0 ; i < t.length ; i++ ) {
			if ( ! t[i].equals(" ") && ! t[i].equals("") ) {
				return false;
			}
		}
		return true;
	}
}